/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { socket } from "@kit.NetworkKit";
import { SocketAddress } from "./SocketAddress";

/**
 * 代理类型枚举
 */
export enum ProxyType {
  /** 无代理 */
  NONE = 0,
  /** SOCKS5 代理 */
  SOCKS5 = 1,
  /** HTTP 代理 */
  HTTP = 2,
  /** 直连（不使用代理） */
  DIRECT = 3,
}

/**
 * 代理配置类
 *
 * 设计说明：
 * - 与原版 OkHttp (java.net.Proxy) 保持一致，仅存储代理类型和地址
 * - HTTP 代理的认证通过 ProxyAuthenticator 处理，不在此类中存储凭证
 * - SOCKS5 代理可以在连接时通过底层 socket API 传递凭证
 *
 * 支持以下代理类型：
 * - DIRECT: 直接连接，不使用代理
 * - HTTP: HTTP 代理（CONNECT 方法）
 * - SOCKS5: SOCKS5 代理
 *
 * 使用示例：
 * ```typescript
 * // 直连
 * const noProxy = Proxy.NO_PROXY;
 *
 * // HTTP 代理（无认证）
 * const httpProxy = Proxy.createHttpProxy('proxy.example.com', 8080);
 *
 * // HTTP 代理（带认证）- 需要配置 ProxyAuthenticator
 * const client = new OkHttpClient.Builder()
 *   .proxy(Proxy.createHttpProxy('proxy.example.com', 8080))
 *   .proxyAuthenticator(ProxyAuthenticator.basic('user', 'pass'))
 *   .build();
 *
 * // SOCKS5 代理
 * const socks5Proxy = Proxy.createSocks5Proxy('socks.example.com', 1080);
 * ```
 */
export class Proxy {
  private _proxyType: ProxyType;
  private _address: SocketAddress | null;

  /** 无代理实例（直连） */
  static NO_PROXY = new Proxy();

  /**
   * 构造函数
   * @param type 代理类型
   * @param address 代理服务器地址
   */
  constructor(type?: ProxyType, address?: SocketAddress) {
    // 处理无参数情况（直连）
    if ((type === null || type === undefined) && (address === null || address === undefined)) {
      this._proxyType = ProxyType.DIRECT;
      this._address = null;
      return;
    }

    // 设置代理类型
    this._proxyType = type ?? ProxyType.DIRECT;
    this._address = address ?? null;
  }

  /**
   * 获取代理类型
   */
  get proxyType(): ProxyType {
    return this._proxyType;
  }

  /**
   * 获取代理地址
   */
  get address(): SocketAddress | null {
    return this._address;
  }

  /**
   * 检查是否为直连（不使用代理）
   */
  isDirect(): boolean {
    return this._proxyType === ProxyType.DIRECT || this._proxyType === ProxyType.NONE;
  }

  /**
   * 检查是否为 HTTP 代理
   */
  isHttpProxy(): boolean {
    return this._proxyType === ProxyType.HTTP;
  }

  /**
   * 检查是否为 SOCKS5 代理
   */
  isSocks5Proxy(): boolean {
    return this._proxyType === ProxyType.SOCKS5;
  }

  /**
   * 获取代理主机地址
   */
  getHost(): string | null {
    return this._address?.address ?? null;
  }

  /**
   * 获取代理端口
   */
  getPort(): number | null {
    return this._address?.port ?? null;
  }

  /**
   * 转换为鸿蒙 socket.ProxyOptions 格式（用于 SOCKS5）
   * 注意：HTTP 代理不使用此方法
   *
   * @param username SOCKS5 代理用户名（可选）
   * @param password SOCKS5 代理密码（可选）
   */
  toProxyOptions(username?: string, password?: string): socket.ProxyOptions | undefined {
    if (this.isDirect()) {
      return undefined;
    }

    if (this.isSocks5Proxy()) {
      return {
        type: socket.ProxyTypes.SOCKS5,
        address: this._address ?? undefined,
        username: username,
        password: password
      };
    }

    // HTTP 代理在 socket 层不设置代理选项
    return undefined;
  }

  /**
   * 比较两个代理是否相等
   */
  equals(other: unknown): boolean {
    if (!(other instanceof Proxy)) {
      return false;
    }

    if (this === other) {
      return true;
    }

    if (this._proxyType !== other._proxyType) {
      return false;
    }

    if (this.isDirect() && other.isDirect()) {
      return true;
    }

    return this._address === other._address ||
      (this._address !== null && other._address !== null && this._address.equals(other._address));
  }

  /**
   * 计算哈希值
   */
  hashCode(): number {
    let result = 17;
    result = 31 * result + this._proxyType;
    if (this._address) {
      result = 31 * result + this.stringHashCode(this._address.address);
      result = 31 * result + (this._address.port ?? 0);
    }
    return result;
  }

  private stringHashCode(str: string): number {
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      hash = ((hash << 5) - hash) + str.charCodeAt(i);
      hash = hash & hash;
    }
    return hash;
  }

  /**
   * 转换为字符串表示
   */
  toString(): string {
    if (this.isDirect()) {
      return 'Proxy[DIRECT]';
    }

    const typeStr = ProxyType[this._proxyType];
    const addressStr = this._address ? `${this._address.address}:${this._address.port}` : 'null';

    return `Proxy[${typeStr} ${addressStr}]`;
  }

  // ==================== 静态工厂方法 ====================

  /**
   * 创建直连代理（不使用代理）
   */
  static direct(): Proxy {
    return Proxy.NO_PROXY;
  }

  /**
   * 创建 HTTP 代理
   *
   * 注意：HTTP 代理认证需要通过 OkHttpClient.Builder.proxyAuthenticator() 配置
   *
   * @param host 代理服务器主机
   * @param port 代理服务器端口
   */
  static createHttpProxy(host: string, port: number): Proxy {
    const address = new SocketAddress(host, port);
    return new Proxy(ProxyType.HTTP, address);
  }

  /**
   * 创建 SOCKS5 代理
   *
   * 注意：SOCKS5 代理认证凭证在建立连接时传递
   *
   * @param host 代理服务器主机
   * @param port 代理服务器端口
   */
  static createSocks5Proxy(host: string, port: number): Proxy {
    const address = new SocketAddress(host, port);
    return new Proxy(ProxyType.SOCKS5, address);
  }

  /**
   * 从 URL 字符串解析代理配置
   *
   * 支持格式：
   * - http://host:port
   * - socks5://host:port
   *
   * 注意：URL 中的用户名密码会被忽略，认证需要单独配置
   */
  static fromUrl(proxyUrl: string): Proxy {
    if (!proxyUrl || proxyUrl.toLowerCase() === 'direct') {
      return Proxy.NO_PROXY;
    }

    try {
      // 简单的 URL 解析
      const urlPattern = /^(https?|socks5?):\/\/(?:[^@]+@)?([^:\/]+)(?::(\d+))?/i;
      const match = proxyUrl.match(urlPattern);

      if (!match) {
        console.error(`[Proxy] Invalid proxy URL format: ${proxyUrl}`);
        return Proxy.NO_PROXY;
      }

      const protocol = match[1].toLowerCase();
      const host = match[2];
      const port = match[3] ? parseInt(match[3]) : (protocol.startsWith('http') ? 8080 : 1080);

      switch (protocol) {
        case 'http':
        case 'https':
          return Proxy.createHttpProxy(host, port);
        case 'socks5':
        case 'socks':
          return Proxy.createSocks5Proxy(host, port);
        default:
          console.warn(`[Proxy] Unknown proxy protocol: ${protocol}, using HTTP`);
          return Proxy.createHttpProxy(host, port);
      }
    } catch (e) {
      console.error(`[Proxy] Failed to parse proxy URL: ${proxyUrl}`, e);
      return Proxy.NO_PROXY;
    }
  }

  /**
   * 从环境变量创建代理（如果存在）
   * 检查 HTTP_PROXY, HTTPS_PROXY, NO_PROXY 等环境变量
   */
  static fromEnvironment(targetHost?: string): Proxy {
    // 鸿蒙系统中获取环境变量的方式可能不同
    // 这里提供一个占位实现
    return Proxy.NO_PROXY;
  }
}
